import { get } from './get';

function createEmpty<T>(source: T) {
  return (Array.isArray(source) ? [] : {}) as T;
}

export type Path = (string | number)[];

//注： {...undefined} === undefined, ...undefined 会报错，  [path,...resePath] = ['name'] resePath === []， {name,...resetObj} = {name:'zyj'} resetObj === {}
function _internalSet<Store = any, Output = Store, Value = any>(
  entity: Store,
  paths: (string | number)[],
  value: Value,
  removeIfUndefined: boolean,
): Output {
  if (!paths.length) {
    return value as unknown as Output;
  }

  const [path, ...restPath] = paths;

  let clone: Output;
  if (!entity && typeof path === 'number') {
    clone = [] as unknown as Output;
  } else if (Array.isArray(entity)) {
    clone = [...entity] as unknown as Output;
  } else {
    clone = { ...entity } as unknown as Output;
  }

  // Delete prop if `removeIfUndefined` and value is undefined
  if (removeIfUndefined && value === undefined && restPath.length === 1) {
    delete (clone as any)[path][restPath[0]];
  } else {
    (clone as any)[path] = _internalSet(
      (clone as any)[path],
      restPath,
      value,
      removeIfUndefined,
    );
  }

  return clone;
}

/**
 *
 *
 * @export
 * @template Entity
 * @template Output
 * @template Value
 * @param {Store} entity 默认 {} {user:{name:'zyj'}} / {'users':[{name:'zyj'}]}
 * @param {((string | number)[])} paths  ['user','name'] / ['users',0,'name']
 * @param {Value} value 'zyj1'
 * @param {boolean} [removeIfUndefined=false]
 * @returns {Output}  1.嵌套['user','name']  'zyj1' => {user:{name:'zyj1'}}， 2.List嵌套 ['users',0,'name']  'zyj1' => {'users':[{name:'zyj1'}]}
 */
export function set<Store = any, Output = Store, Value = any>(
  entity: Store,
  paths: (string | number)[],
  value: Value,
  removeIfUndefined: boolean = false,
): Output {
  // Do nothing if `removeIfUndefined` and parent object not exist
  if (
    paths.length &&
    removeIfUndefined &&
    value === undefined &&
    !get(entity, paths.slice(0, -1)) // -1：倒数第1个数， ['users',0,'name'].slice(0,-1) === ['users',0]  (>=0 <-1)   /   ['users',0,'name'].slice(0,array.length -1) ===  ['users',0]  /  ['name'].slice(0,-1) === []
  ) {
    return entity as unknown as Output;
  }

  return _internalSet(entity, paths, value, removeIfUndefined);
}

function isObject(obj: any) {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    Object.getPrototypeOf(obj) === Object.prototype
  );
}
